package main

import (
	"bufio"
	"fmt"
	"os"
	"parse/src/configs"
	"parse/src/events/termbox-go"
	"parse/src/globals"
	"parse/src/interpreter"
	"parse/src/params"
	"parse/src/repl"
	"parse/src/utils"
	"strings"
)

// 输入的内容字符串的数组
var EditBoxArr []termbox.EditBox

// 字符串中数组的索引
var EditBoxArrIndex = 0

// 全局的上下文
var contextObj *interpreter.Context
var interpreterObj *interpreter.Interpreter

// 初始化数据
func initData() bool {
	//解析配置文件,内容存在 globals.Configs 里面
	res := configs.ParseConfig(nil)
	if res.Error_ != nil {
		utils.PrintErr(res.Error_.ToString())
		return false
	}
	// 得到一个 token(ast) 的翻译器
	interpreterObj = interpreter.NewInterpreter()
	// 实例化一个context上下文
	contextObj = interpreter.NewContext("运行程序", nil, nil)
	// 实例化一个SymbolTable（符号表）,符号表里面存储了所有的系统函数，以及对象等
	contextObj.SymbolTable = interpreter.GlobalSymbolTable
	return true
}

func main() {

	// 得到参数 文件
	args := os.Args[1:]
	// 初始化数据
	if !initData() {
		return
	}
	// 没有传递参数，表示是进入该程序
	if len(args) == 0 {
		run()
	} else {
		// 传递了参数，表示是运行某一个文件里面的程序内容,第一个参数必须为文件名字
		params.DealParams(args, interpreterObj, contextObj)
	}
}

// 过输入上下按键来进行数据填充
func run() {
	switch configs.GetConfig("TESTTYPE") {
	case 1: //  调试版本
		drawKeyboard1()
		for true {
			input := strings.Trim(GetInputByScanner(), " ")
			if input != "" {
				result, err := repl.Start(input, contextObj, interpreterObj) // 开始运行程序
				utils.Println("输出：")
				interpreter.DealResult(result, err)
			}
		}
	case 2: // 上线版本 1
		// 实时获取键盘的输入，然后将命令拿到到控制台上面
		err := termbox.Init()
		if err != nil {
			panic(err)
		}
		defer termbox.Close()
		termbox.SetInputMode(termbox.InputEsc)

		_ = termbox.Clear(Coldef, Coldef)
		drawKeyboard2()
		globals.EditBoxObj.CursorLineOffset = startIndex
		clearCursor(len(startStr), globals.EditBoxObj.CursorLineOffset)
		_ = termbox.Flush()
	mainLoop:
		for {
			switch ev := termbox.PollEvent(); ev.Type {
			case termbox.EventKey: // 处理所有的按键以及输入数据
				switch ev.Key {
				case termbox.KeyEsc:
					break mainLoop
				case termbox.KeyArrowLeft, termbox.KeyCtrlB:
					globals.EditBoxObj.MoveCursorOneRuneBackward()
				case termbox.KeyArrowRight, termbox.KeyCtrlF:
					globals.EditBoxObj.MoveCursorOneRuneForward()
				case termbox.KeyArrowUp: // 按键向上就是把上一个记录填充进控制台
					tianchongCmdUp(true)
				case termbox.KeyArrowDown: // 按键向下就是把上一个记录填充进控制台
					tianchongCmdUp(false)
				case termbox.KeyCtrlQ: // ctrl+q清屏
					cleanConsole()
				case termbox.KeyBackspace, termbox.KeyBackspace2:
					globals.EditBoxObj.DeleteRuneBackward()
				case termbox.KeyDelete, termbox.KeyCtrlD:
					globals.EditBoxObj.DeleteRuneForward()
				case termbox.KeyTab:
					globals.EditBoxObj.InsertRune('\t')
				case termbox.KeySpace:
					globals.EditBoxObj.InsertRune(' ')
				case termbox.KeyCtrlK:
					globals.EditBoxObj.DeleteTheRestOfTheLine()
				case termbox.KeyHome, termbox.KeyCtrlA:
					globals.EditBoxObj.MoveCursorToBeginningOfTheLine()
				case termbox.KeyEnd, termbox.KeyCtrlE:
					globals.EditBoxObj.MoveCursorToEndOfTheLine()
				case termbox.KeyCtrlC: // ctrl+c按键退出程序
					os.Exit(1)
				case termbox.KeyEnter:
					if len(globals.EditBoxObj.Text) <= 0 {
						continue
					}
					result, err := repl.Start(string(globals.EditBoxObj.Text), contextObj, interpreterObj) // 开始运行程序
					utils.Println("输出：")
					interpreter.DealResult(result, err)
					utils.Println(startStr)
					// 先将命令行数据进行缓存
					EditBoxArr = append(EditBoxArr, globals.EditBoxObj)
					// 清空数据
					globals.EditBoxObj.Text = nil
					globals.EditBoxObj.CursorBoffset = 0
					globals.EditBoxObj.CursorCoffset = 0
					globals.EditBoxObj.CursorVoffset = 0
					// 移到行的第一个位置
					globals.EditBoxObj.MoveCursorToBeginningOfTheLine()
					// 数组索引变成0
					EditBoxArrIndex = 0

				default:
					if ev.Ch != 0 {
						globals.EditBoxObj.InsertRune(ev.Ch)
					}
				}
			case termbox.EventError:
				panic(ev.Err)
			}
			drawKeyboard_()

			clearCursor(len(startStr), globals.EditBoxObj.CursorLineOffset)

			_ = termbox.Flush()
		}
	}
}

// 开始输出
var startStr = ">> "

// 开始的行数
var startIndex = 0

const Coldef = termbox.ColorDefault
const EditBoxWidth = 120

func drawKeyboard1() {
	fmt.Println("欢迎使用该程序：")
	fmt.Println("本程序作者-余飞：")
	fmt.Println("输入ctrl+c退出。")
	fmt.Println("输入ctrl+q清屏，输入上下按键获取历史命令语句。")
}
func drawKeyboard2() {
	startIndex = 0
	termbox.Tbprint(0, startIndex, Coldef, Coldef, "欢迎使用该程序：")
	startIndex++
	termbox.Tbprint(0, startIndex, Coldef, Coldef, "本程序作者-余飞：")
	startIndex++
	termbox.Tbprint(0, startIndex, Coldef, Coldef, "输入ctrl+c退出。")
	startIndex++
	termbox.Tbprint(0, startIndex, Coldef, Coldef, "输入ctrl+q清屏，输入上下按键获取历史命令语句。")
	startIndex++
	termbox.Tbprint(0, startIndex, Coldef, Coldef, startStr)
}
func drawKeyboard_() {
	startIndex = 0
}
func clearCursor(x int, y int) {
	w, _ := termbox.Size()
	globals.EditBoxObj.Draw(x, y, w-10, 1)
	termbox.SetCursor(x+globals.EditBoxObj.CursorX(), y)
}

// 填充索引为 index 的数据 ，表示从数组最后一个数， 1表示最后一个
func tianchongCmdUp(status bool) {
	if EditBoxArr == nil {
		return
	}
	if status {
		EditBoxArrIndex++
	} else {
		EditBoxArrIndex--
	}
	if EditBoxArrIndex > len(EditBoxArr) { // 第一个
		EditBoxArrIndex = len(EditBoxArr)
	}
	if EditBoxArrIndex < 1 { // 表示的意思是已经到了最后一个了
		EditBoxArrIndex = 1
	}
	index := len(EditBoxArr) - EditBoxArrIndex

	cmd := EditBoxArr[index]
	// 移到行的第一个位置
	globals.EditBoxObj.MoveCursorToBeginningOfTheLine()
	// 依次输出内容
	termbox.Tbprint(len(startStr), globals.EditBoxObj.CursorLineOffset, Coldef, Coldef, string(cmd.Text))
	globals.EditBoxObj.Text = cmd.Text
	globals.EditBoxObj.MoveCursorTo(len(cmd.Text))
}

// 清屏
func cleanConsole() {
	_ = termbox.Clear(Coldef, Coldef)
	drawKeyboard2()
	globals.EditBoxObj.CursorLineOffset = startIndex
	clearCursor(len(startStr), globals.EditBoxObj.CursorLineOffset)
	_ = termbox.Flush()
}

// 得到输入的字符串
func GetInputByScanner() string {
	fmt.Print(startStr)
	//使用os.Stdin开启输入流
	in := bufio.NewScanner(os.Stdin)
	if in.Scan() {
		return in.Text()
	}
	return ""
}
